package com.cz.mydao.dao;

import com.cz.mydao.annotation.PrimaryKey;
import com.cz.mydao.annotation.Table;
import com.cz.mydao.annotation.TableField;
import com.cz.mydao.constant.Constant;
import com.cz.mydao.constant.SqlKey;
import com.cz.mydao.enumeration.DeleteType;
import com.cz.mydao.enumeration.FillPolicy;
import com.cz.mydao.enumeration.IdType;
import com.cz.mydao.pool.CustomConnectionPool;
import com.cz.mydao.wrapper.DeleteWrapper;
import com.cz.mydao.wrapper.SelectWrapper;
import com.cz.mydao.wrapper.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @descriptions: 抽象DAO 实现DAO接口中mysql和sqlserver相同语法的方法，
 * 有差异的语法定义成抽象方法，让子类继承去实现
 * @author: Joker.
 * @date: 2024/12/27 14:39
 * @version: 1.0
 */

@Slf4j
@SuppressWarnings("unchecked")
public abstract class AbstractBaseDao<T> implements Dao<T> {

    /**
     * 数据库数据源
     */
    @Resource
    protected CustomConnectionPool connectionPool;

    /**
     * 表名
     */
    protected String tableName;

    /**
     * 泛型类型对象的字节码
     */
    private Class<T> clazz;

    /**
     * 初始化类的字节码，对应在数据库中的表名
     */
    @PostConstruct
    public void init() {
        // 获取泛型T的类型
        Type genericSuperclass = getClass().getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType) genericSuperclass;
            // 获取实际类型参数
            clazz = (Class<T>) type.getActualTypeArguments()[0];
            // 获取类的 @Table 注解
            if (clazz.isAnnotationPresent(Table.class)) {
                Table tableAnnotation = clazz.getAnnotation(Table.class);
                // 获取表名
                this.tableName = tableAnnotation.name();
            }

        }
    }

    /**
     * 获取数据库连接
     *
     * @return 数据库连接
     */
    @Override
    public Connection getConnection() {
        try {
            return connectionPool.getConnection();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据注解创建表
     *
     * @param tableName 表名
     */
    @Override
    public void createTable(String tableName) {
        StringBuilder sql = new StringBuilder(SqlKey.CREATE_TABLE).append(tableName).append(SqlKey.LEFT_BRACKET);
        for (Field field : clazz.getDeclaredFields()) {
            // 拼接主键的列名，类型等
            this.createTablePrimaryKey(field, sql);
            // 拼接其他表字段的列名，类型等
            this.createTableField(field, sql);
        }
        // 拼接定义主键sql
        this.createTableDefinePrimaryKey(sql);
        log.info(sql.toString());
        // 执行 SQL 语句
        this.executeCreateTable(tableName, sql);
    }

    /**
     * 执行建表的SQL语句
     *
     * @param tableName 表名
     * @param sql       sql
     */
    private void executeCreateTable(String tableName, StringBuilder sql) {
        try (Connection connection = connectionPool.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(sql.toString())) {
            preparedStatement.executeUpdate();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.CREATE_TABLE_FAIL + tableName, e);
        }
    }

    /**
     * 创建表时定义表主键
     *
     * @param sql sql
     */
    private void createTableDefinePrimaryKey(StringBuilder sql) {
        sql.append(SqlKey.PRIMARY_KEY).append(SqlKey.LEFT_BRACKET);
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(PrimaryKey.class)) {
                sql.append(field.getAnnotation(PrimaryKey.class).columnName());
            }
        }
        sql.append(SqlKey.RIGHT_BRACKET).append(SqlKey.RIGHT_BRACKET);
    }

    /**
     * 创建表时拼接其他表字段的列名，类型等
     *
     * @param field 表字段
     * @param sql   sql
     */
    private void createTableField(Field field, StringBuilder sql) {
        if (field.isAnnotationPresent(TableField.class)) {
            TableField annotation = field.getAnnotation(TableField.class);
            // 拼接 列名 数据类型 是否为空 comment '字段描述'
            sql.append(annotation.columnName()).append(SqlKey.SPACE)
                    .append(annotation.fieldType()).append(SqlKey.SPACE)
                    .append(annotation.isNullable()).append(SqlKey.SPACE)
                    .append(SqlKey.COMMENT).append(SqlKey.SINGLE_QUOTATION_MARK)
                    .append(annotation.comment())
                    .append(SqlKey.SINGLE_QUOTATION_MARK)
                    .append(SqlKey.COMMA);
        }
    }

    /**
     * 创建表时拼接主键的列名，类型等
     *
     * @param field 表字段
     * @param sql   sql
     */
    private void createTablePrimaryKey(Field field, StringBuilder sql) {
        if (field.isAnnotationPresent(PrimaryKey.class)) {
            PrimaryKey annotation = field.getAnnotation(PrimaryKey.class);
            // 拼接 列名 主键的数据类型 是否为空 增长类型 '字段描述'
            sql.append(annotation.columnName()).append(SqlKey.SPACE)
                    .append(annotation.fieldType()).append(SqlKey.SPACE)
                    .append(annotation.isNullable()).append(SqlKey.SPACE)
                    .append(annotation.type()).append(SqlKey.SPACE)
                    .append(SqlKey.COMMENT).append(SqlKey.SINGLE_QUOTATION_MARK)
                    .append(annotation.comment())
                    .append(SqlKey.SINGLE_QUOTATION_MARK)
                    .append(SqlKey.COMMA);
        }
    }

    /**
     * 创建视图方法
     *
     * @param viewName    视图名字
     * @param selectQuery 查询语句
     */
    @Override
    public void createView(String viewName, String selectQuery) {
        // 构建创建视图sql
        String sql = SqlKey.CREATE_VIEW + viewName + SqlKey.AS + selectQuery;
        log.info(sql);
        try {
            Connection connection = connectionPool.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 执行sql
            preparedStatement.executeUpdate();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.CREATE_VIEW_FAIL + viewName, e);
        }
    }


    /**
     * 根据id查询信息并封装到实体类中
     *
     * @param id id
     * @return 实体类
     */
    @Override
    public T queryById(Long id) {
        // 拼接查询sql
        String sql = SqlKey.SELECT_ASTERISK_FROM + tableName + SqlKey.WHERE + id + SqlKey.EQUALS + SqlKey.QUESTION_MARK;
        log.info(sql);
        try {
            Connection connection = connectionPool.getConnection();
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setLong(1, id);
            List<T> tList = this.executeQuerySql(preparedStatement);
            if (tList == null) {
                throw new RuntimeException(Constant.QUERY_FAIL);
            }
            return tList.get(0);
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.QUERY_FAIL, e);
        }
    }

    /**
     * 根据ids批量查询
     *
     * @param ids id集合
     * @return 查询结果
     */
    @Override
    public List<T> queryListByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return null;
        }
        // 根据ids批量查询构造sql
        StringBuilder sql = queryListByIdsBuildSql(ids);
        try {
            // 预编译并向占位符赋值
            PreparedStatement preparedStatement = queryListByIdsPrepared(ids, sql);
            // 执行sql
            return executeQuerySql(preparedStatement);
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.QUERY_FAIL, e);
        }
    }

    /**
     * 根据ids批量的预编译并向占位符赋值
     *
     * @param ids id集合
     * @param sql sql
     * @return 预编译
     */
    private PreparedStatement queryListByIdsPrepared(List<Long> ids, StringBuilder sql) throws InterruptedException, SQLException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
        // 向占位符赋值
        for (int index = 0; index < ids.size(); index++) {
            preparedStatement.setLong(index + 1, ids.get(index));
        }
        return preparedStatement;
    }

    /**
     * 根据ids批量查询构造sql
     *
     * @param ids id集合
     * @return sql
     */
    private StringBuilder queryListByIdsBuildSql(List<Long> ids) {
        StringBuilder sql = new StringBuilder(SqlKey.SELECT_ASTERISK_FROM + tableName + SqlKey.WHERE + SqlKey.ID + SqlKey.IN + SqlKey.LEFT_BRACKET);
        for (int index = 0; index < ids.size(); index++) {
            sql.append(SqlKey.QUESTION_MARK);
            if (index < ids.size() - 1) {
                sql.append(SqlKey.COMMA);
            }
        }
        sql.append(SqlKey.RIGHT_BRACKET);
        return sql;
    }

    /**
     * 条件查询
     *
     * @param wrapper 查询条件
     * @return 查询结果
     */
    @Override
    public List<T> query(SelectWrapper wrapper) {
        if (wrapper == null) {
            return null;
        }
        // 根据封装的查询条件构造条件查询sql
        String sql = wrapper.buildSql(tableName);
        log.info(sql);
        try {
            //条件查询的预编译及向占位符赋值
            PreparedStatement preparedStatement = queryPrepared(wrapper, sql);
            // 执行查询sql并返回结果
            return this.executeQuerySql(preparedStatement);
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.QUERY_FAIL, e);
        }
    }

    /**
     * 条件查询的预编译及向占位符赋值
     *
     * @param wrapper 条件
     * @param sql     sql
     * @return 预编译
     */
    private PreparedStatement queryPrepared(SelectWrapper wrapper, String sql) throws InterruptedException, SQLException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        // 向占位符赋值
        List<Object> values = wrapper.getValues();
        for (int index = 0; index < values.size(); index++) {
            preparedStatement.setObject(index + 1, values.get(index));
        }
        return preparedStatement;
    }

    /**
     * 抽象分页条件查询 交给子类实现
     *
     * @param page     第几页
     * @param pageSize 每页多少条
     * @param wrapper  条件
     * @return 查询结果
     */
    @Override
    public abstract List<T> pageQuery(Long page, Long pageSize, SelectWrapper wrapper);

    /**
     * 插入
     *
     * @param object 要插入的对象
     * @return 影响行数
     */
    @Override
    public Integer insert(T object) {
        // 填充时间字段
        this.autoFillField(object);
        // 存放表字段
        List<Field> tableField = new ArrayList<>();
        // 构建sql
        StringBuilder sql = buildInsertSql(tableField);
        log.info(sql.toString());

        try {
            //插入操作的预编译处理及向占位符赋值
            PreparedStatement preparedStatement = insertPrepared(object, sql, tableField);
            // 执行插入sql 返回成功插入的记录数
            return preparedStatement.executeUpdate();
        } catch (SQLException | IllegalAccessException | InterruptedException e) {
            throw new RuntimeException(Constant.INSERT_FAIL, e);
        }
    }

    /**
     * 插入操作的预编译处理及向占位符赋值
     *
     * @param object     插入对象
     * @param sql        插入sql
     * @param tableField 表字段
     * @return 预编译
     */
    private PreparedStatement insertPrepared(T object, StringBuilder sql, List<Field> tableField) throws InterruptedException, SQLException, IllegalAccessException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
        // 向占位符赋值
        for (int index = 0; index < tableField.size(); index++) {
            Field field = tableField.get(index);
            field.setAccessible(true);
            // 获取字段的值
            Object value = field.get(object);
            // 向占位符赋值
            preparedStatement.setObject(index + 1, value);
        }
        return preparedStatement;
    }

    /**
     * 批量插入
     *
     * @param objectList 要插入的对象列表
     * @return 影响行数
     */
    @Override
    public Integer insertBatch(List<T> objectList) {

        if (objectList == null || objectList.isEmpty()) {
            return 0;
        }
        // 填充字段
        for (T object : objectList) {
            this.autoFillField(object);
        }
        // 存放表字段
        List<Field> tableField = new ArrayList<>();
        // 构建sql
        StringBuilder sql = buildInsertSql(tableField);
        log.info(sql.toString());

        try {
            // 执行批量插入sql
            int[] rows = insertBatchExecute(objectList, sql, tableField);
            // 返回成功插入的记录数
            return rows.length;
        } catch (SQLException | InterruptedException | IllegalAccessException e) {
            throw new RuntimeException(Constant.INSERT_BATCH_FAIL, e);
        }
    }

    /**
     * 执行批量插入sql
     *
     * @param objectList 批量插入的对象
     * @param sql        sql
     * @param tableField 表字段
     * @return 影响行数
     */
    private int[] insertBatchExecute(List<T> objectList, StringBuilder sql, List<Field> tableField) throws InterruptedException, SQLException, IllegalAccessException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());

        // 设置事务手动提交
        connection.setAutoCommit(false);

        // 批量插入时遍历表字段向占位符赋值
        insertBatchAssignment(objectList, tableField, preparedStatement);
        // 执行批量插入
        int[] rows = preparedStatement.executeBatch();
        //提交事务
        connection.commit();
        return rows;
    }

    /**
     * 批量插入时遍历表字段向占位符赋值
     *
     * @param objectList        对象列表
     * @param tableField        表字段
     * @param preparedStatement 预编译
     */
    private void insertBatchAssignment(List<T> objectList, List<Field> tableField, PreparedStatement preparedStatement) throws IllegalAccessException, SQLException {
        for (T object : objectList) {
            // 批量插入向占位符赋值
            insertBatchSetValues(tableField, preparedStatement, object);
            preparedStatement.addBatch();
        }
    }

    /**
     * 批量插入向占位符赋值
     *
     * @param tableField        表字段
     * @param preparedStatement 预编译
     * @param object            插入对象
     */
    private void insertBatchSetValues(List<Field> tableField, PreparedStatement preparedStatement, T object) throws IllegalAccessException, SQLException {
        for (int index = 0; index < tableField.size(); index++) {
            Field field = tableField.get(index);
            field.setAccessible(true);
            // 获取字段的值
            Object value = field.get(object);
            // 向占位符赋值
            preparedStatement.setObject(index + 1, value);
        }
    }

    /**
     * 默认根据id修改整行数据
     *
     * @param object 修改的数据对象
     * @return 影响行数
     */
    @Override
    public Integer updateById(T object) {
        // 存放修改的值
        List<Object> values = new ArrayList<>();
        try {
            // 根据id修改对象预编译操作
            PreparedStatement preparedStatement = updateByIdPrepared(object, values);
            return preparedStatement.executeUpdate();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.UPDATE_FAIL, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(Constant.MAPPING_FAIL, e);
        }
    }

    /**
     * 根据id修改对象预编译操作
     *
     * @param object 修改对象
     * @param values 修改值
     * @return 预编译
     */
    private PreparedStatement updateByIdPrepared(T object, List<Object> values) throws IllegalAccessException, InterruptedException, SQLException {
        // 生成插入sql
        String sql = buildUpdateLineSql(object, values);
        log.info(sql);
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        // 向占位符赋值
        for (int index = 0; index < values.size(); index++) {
            preparedStatement.setObject(index + 1, values.get(index));
        }
        return preparedStatement;
    }

    /**
     * 根据条件修改指定列
     *
     * @param wrapper 条件
     * @return 影响行数
     */
    @Override
    public Integer update(UpdateWrapper wrapper) {
        if (wrapper == null) {
            return null;
        }
        // 生成update sql
        String sql = wrapper.buildSql(tableName);
        log.info(sql);
        try {
            // 根据条件修改的预编译操作
            PreparedStatement preparedStatement = updatePrepared(wrapper, sql);
            // 执行sql并返回影响行数
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据条件修改的预编译操作
     *
     * @param wrapper 修改条件
     * @param sql     修改sql
     * @return 预编译
     */
    private PreparedStatement updatePrepared(UpdateWrapper wrapper, String sql) throws InterruptedException, SQLException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        // 取出set后面的值 即set name = ？
        Map<String, Object> updateValues = wrapper.getUpdateValues();
        // 取出where后面的值 即 where dept_name = ?
        List<Object> values = wrapper.getValues();
        // 合并，将修改值放在条件值前面
        Collection<Object> values1 = updateValues.values();
        values.addAll(0, values1);
        for (int index = 0; index < values.size(); index++) {
            // 向占位符赋值
            preparedStatement.setObject(index + 1, values.get(index));
        }
        return preparedStatement;
    }

    /**
     * 执行sql语句并将执行结果映射为Java对象
     *
     * @param preparedStatement 预编译
     * @return 查询对象集合
     */
    protected List<T> executeQuerySql(PreparedStatement preparedStatement) throws SQLException {
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        // 查询出数据的列数
        int columnCount = metaData.getColumnCount();
        List<T> tList = new ArrayList<>();
        while (resultSet.next()) {
            try {
                T entity = clazz.getDeclaredConstructor().newInstance();

                for (int index = 1; index <= columnCount; index++) {
                    // 查询出来的列名
                    String columnLabel = metaData.getColumnLabel(index);
                    // 遍历表字段，从sql执行结果中的列与实体类的字段匹配进行赋值
                    setFieldValues(entity, columnLabel, resultSet, index);
                }
                tList.add(entity);
            } catch (Exception e) {
                throw new SQLException(Constant.MAPPING_FAIL, e);
            }
        }
        return tList;
    }

    /**
     * 遍历表字段，从sql执行结果中的列与实体类的字段匹配进行赋值
     *
     * @param entity      实体类
     * @param columnLabel 列名
     * @param resultSet   查询结果
     * @param index       列下标
     */
    private void setFieldValues(T entity, String columnLabel, ResultSet resultSet, int index) throws IllegalAccessException, SQLException {
        for (Field field : entity.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(TableField.class)) {
                // 表字段注解中定义的数据库名
                String fieldName = field.getAnnotation(TableField.class).columnName();
                if (fieldName.equals(columnLabel)) {
                    // 即匹配 赋值
                    field.setAccessible(true);
                    field.set(entity, resultSet.getObject(index));
                }
            }
        }
    }

    /**
     * 根据条件删除
     *
     * @param wrapper 条件
     * @return 影响行数
     */
    @Override
    public Integer deleteByCondition(DeleteWrapper wrapper) {
        // 获取删除类型
        DeleteType deleteType = getDeleteType();
        String sql = wrapper.buildSql(tableName, deleteType);
        log.info(sql);
        try {
            // 根据条件删除预编译操作
            PreparedStatement preparedStatement = deleteByConditionPrepared(wrapper, sql);
            // 执行删除sql，返回删除行数
            return preparedStatement.executeUpdate();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据条件删除预编译操作
     *
     * @param wrapper 删除条件
     * @param sql     删除sql
     * @return 预编译
     */
    private PreparedStatement deleteByConditionPrepared(DeleteWrapper wrapper, String sql) throws InterruptedException, SQLException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if (!wrapper.getValues().isEmpty()) {
            // 获取条件值
            List<Object> values = wrapper.getValues();
            for (int index = 0; index < values.size(); index++) {
                // 向占位符赋值
                preparedStatement.setObject(index + 1, values.get(index));
            }
        }
        return preparedStatement;
    }

    /**
     * 获取删除类型
     *
     * @return 删除类型
     */
    private DeleteType getDeleteType() {
        // 从注解中获取删除方式
        DeleteType deleteType = null;
        if (clazz.isAnnotationPresent(TableField.class)) {
            deleteType = clazz.getAnnotation(Table.class).deleteType();
        }
        return deleteType;
    }


    /**
     * 根据id批量删除
     *
     * @param ids id列表
     * @return 影响行数
     */
    @Override
    public Integer deleteById(List<Long> ids) {
        // 构建删除sql
        StringBuilder sql = deleteByIdBuildSql(ids);
        log.info(sql.toString());

        try {
            // 创建根据ids批量删除的预编译
            PreparedStatement preparedStatement = getPreparedStatement(ids, sql);
            return preparedStatement.executeUpdate();
        } catch (SQLException | InterruptedException e) {
            throw new RuntimeException(Constant.DELETE_FAIL, e);
        }
    }

    /**
     * 创建根据ids批量删除的预编译
     *
     * @param ids 要删除的id集合
     * @param sql 删除sql
     * @return 预编译
     */
    private PreparedStatement getPreparedStatement(List<Long> ids, StringBuilder sql) throws InterruptedException, SQLException {
        Connection connection = connectionPool.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql.toString());
        for (int index = 0; index < ids.size(); index++) {
            // 向占位符赋值
            preparedStatement.setObject(index + 1, ids.get(index));
        }
        return preparedStatement;
    }

    /**
     * 根据id批量删除构造sql
     *
     * @param ids 要删除的id集合
     * @return 删除sql
     */
    private StringBuilder deleteByIdBuildSql(List<Long> ids) {
        StringBuilder sql = new StringBuilder(SqlKey.DELETE + SqlKey.FROM + tableName + SqlKey.WHERE + SqlKey.ID + SqlKey.IN + SqlKey.LEFT_BRACKET);
        for (int index = 0; index < ids.size(); index++) {
            sql.append(SqlKey.QUESTION_MARK);
            if (index < ids.size() - 1) {
                sql.append(SqlKey.COMMA);
            }
        }
        sql.append(SqlKey.RIGHT_BRACKET);
        return sql;
    }

    /**
     * 构建插入sql
     *
     * @param tableField 表字段
     * @return sql
     */
    private StringBuilder buildInsertSql(List<Field> tableField) {
        StringBuilder sql = new StringBuilder(
                SqlKey.INSERT_INTO + tableName + SqlKey.LEFT_BRACKET);
        // 反射获取实体类的所有字段
        Field[] fields = clazz.getDeclaredFields();

        // 拼接插入sql的字段名部分
        buildInsertSqlFieldName(tableField, fields, sql);
        // 拼接sql的values部分
        buildInsertSqlFieldValues(tableField, sql);
        return sql;
    }

    /**
     * 拼接sql的values部分
     *
     * @param tableField 表字段
     * @param sql        插入sql
     */
    private void buildInsertSqlFieldValues(List<Field> tableField, StringBuilder sql) {
        sql.append(SqlKey.RIGHT_BRACKET).append(SqlKey.VALUES).append(SqlKey.LEFT_BRACKET);
        for (int index = 0; index < tableField.size(); index++) {
            sql.append(SqlKey.QUESTION_MARK);
            if (index < tableField.size() - 1) {
                sql.append(SqlKey.COMMA);
            }
        }
        sql.append(SqlKey.RIGHT_BRACKET);
    }

    /**
     * 拼接插入sql的字段名部分
     *
     * @param tableField 表字段
     * @param fields     对应的实体类的属性字段
     * @param sql        sql
     */
    private void buildInsertSqlFieldName(List<Field> tableField, Field[] fields, StringBuilder sql) {
        for (int index = 0; index < fields.length; index++) {
            // 判断有主键注解的字段填充类型
            isPrimaryKeyFillPolicy(tableField, fields, sql, index);
            // 通过注解判断如果是表字段，加入到表字段集合
            if (fields[index].isAnnotationPresent(TableField.class)) {
                tableField.add(fields[index]);
                // 从表字段注解的属性中获取列名
                sql.append(fields[index].getAnnotation(TableField.class).columnName());
                if (index < fields.length - 1) {
                    sql.append(SqlKey.COMMA);
                }
            }
        }
    }

    /**
     * 判断有主键注解的字段填充类型
     *
     * @param tableField 表字段
     * @param fields     对应的实体类的属性字段
     * @param sql        插入sql
     * @param index      下标
     */
    private void isPrimaryKeyFillPolicy(List<Field> tableField, Field[] fields, StringBuilder sql, int index) {
        if (fields[index].isAnnotationPresent(PrimaryKey.class)) {
            // 如果id填充方式为UUID, 即需要手动填充id
            if (IdType.UUID.equals(fields[index].getAnnotation(PrimaryKey.class).type())) {
                tableField.add(fields[index]);
                sql.append(fields[index].getAnnotation(PrimaryKey.class).columnName()).append(SqlKey.COMMA);
            }
        }
    }

    /**
     * 生成修改整行数据的sql
     *
     * @param object 对象
     * @return sql
     */
    protected String buildUpdateLineSql(T object, List<Object> values) throws IllegalAccessException {
        StringBuilder sql = new StringBuilder(SqlKey.UPDATE + tableName + SqlKey.SET);

        Field[] fields = object.getClass().getDeclaredFields();
        // 构建修改sql的 set = ？ 部分
        buildUpdateSqlSet(object, values, fields, sql);

        // 默认取id为修改操作的where条件
        fields[0].setAccessible(true);
        sql.append(fields[0].getAnnotation(PrimaryKey.class).columnName())
                .append(SqlKey.EQUALS)
                .append(SqlKey.QUESTION_MARK);
        values.add(fields[0].get(object));
        return sql.toString();
    }

    /**
     * 构建修改sql的 set = ？ 部分
     *
     * @param object 修改的对象
     * @param values 要修改的值
     * @param fields 映射实体类字段
     * @param sql    修改sql
     */
    private void buildUpdateSqlSet(T object, List<Object> values, Field[] fields, StringBuilder sql) throws IllegalAccessException {
        for (Field field : fields) {
            if (field.isAnnotationPresent(TableField.class)) {
                field.setAccessible(true);
                // 拼接set部分 field = ? ,
                sql.append(field.getAnnotation(TableField.class).columnName())
                        .append(SqlKey.EQUALS)
                        .append(SqlKey.QUESTION_MARK)
                        .append(SqlKey.COMMA);
                //得到该字段的值并存入
                values.add(field.get(object));
            }
        }
        // 删除最后一个多余的 ,
        sql.delete(sql.length() - 1, sql.length());
        sql.append(SqlKey.WHERE);
    }


    /**
     * 执行插入操作时填充某些字段的值
     *
     * @param object 要填充的对象
     */
    private void autoFillField(T object) {
        LocalDateTime nowTime = LocalDateTime.now();
        try {
            for (Field field : object.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                // 填充主键
                fillPrimaryKeyValue(object, field);
                // 填充表字段
                fillTableField(object, field, nowTime);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 填充表字段
     *
     * @param object  插入的对象
     * @param field   表字段
     * @param nowTime 当前系统时间
     */
    private void fillTableField(T object, Field field, LocalDateTime nowTime) throws IllegalAccessException {
        if (field.isAnnotationPresent(TableField.class)) {
            // 如果注解的自动填充属性为插入策略
            if (FillPolicy.INSERT.equals(field.getAnnotation(TableField.class).fill())) {
                field.set(object, nowTime);
            }
            // 插入操作同时同步修改时间
            if (FillPolicy.UPDATE.equals(field.getAnnotation(TableField.class).fill())) {
                field.set(object, nowTime);
            }
        }
    }

    /**
     * 填充主键的值
     *
     * @param object 插入的对象
     * @param field  表字段
     */
    private void fillPrimaryKeyValue(T object, Field field) throws IllegalAccessException {
        // 有主键注解的字段
        if (field.isAnnotationPresent(PrimaryKey.class)) {
            // id填充方式为UUID
            if (IdType.UUID.equals(field.getAnnotation(PrimaryKey.class).type())) {
                field.set(object, UUID.randomUUID().toString());
            }
        }
    }
}

